#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include "./ser/server.hpp"
#include <sys/stat.h>

// 字符串分割函数
size_t Split(const std::string &str, const std::string &delim, std::vector<std::string> *res)
{
    size_t offset = 0;
    while (offset < str.size())
    {
        size_t pos = str.find(delim, offset);
        if (pos == std::string::npos)
        {
            if (pos == str.size())
                break;
            res->push_back(str.substr(offset));
            return res->size();
        }
        if (pos > offset)
            res->push_back(str.substr(offset, pos - offset));
        offset = pos + delim.size();
    }
    return res->size();
}

// 读取文件内容
static bool ReadFile(const std::string &path, std::string *buf)
{
    std::ifstream ifs(path, std::ios::binary);
    if (ifs.is_open() == false)
    {
        printf("open file %s failed\n", path.c_str());
        return false;
    }
    size_t size = 0;
    ifs.seekg(0, std::ios::end); // 跳过读写位置到末尾
    size = ifs.tellg();          // 获取当前读位置相对于起始位置的偏移量，从末尾偏移刚好就是文件大小
    ifs.seekg(0, std::ios::beg); // 跳转到起始位置
    buf->resize(size);           // 开辟文件大小的空间
    ifs.read(&(*buf)[0], size);
    if (ifs.good() == false)
    {
        printf("read file %s failed\n", path.c_str());
        ifs.close();
        return false;
    }
    ifs.close();
    return true;
}
static bool WriteFile(std::string &filename, const std::string &buf)
{
    std::ofstream ofs(filename, std::ios::binary | std::ios::trunc);
    if (ofs.is_open() == false)
    {
        printf("open file %s failed\n", filename.c_str());
        return false;
    }
    ofs.write(buf.c_str(), buf.size());
    if (ofs.good() == false)
    {
        // printf("write file %s failed\n",filename.c_str());
        LOG_ERROR("write file %s failed", filename.c_str());
        ofs.close();
        return false;
    }
    return true;
}

static std::string UrlEncode(const std::string &url, bool convert_space_to_plus)
{
    std::string res;
    for (auto c : url)
    {
        if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~')
        {
            res += c; // 保留字符
            continue;
        }
        if (convert_space_to_plus && c == ' ')
        {
            res += '+'; // 转换空格为+
            continue;
        }
        // 剩下的字符都是需要编码为%HH的格式
        char buf[4] = {0};
        snprintf(buf, 4, "%%%02X", c);
        res += buf;
    }
    return res;
}

static char HEXTOI(char c)
{
    if (c >= '0' && c <= '9')
    {
        return c - '0';
    }
    if (c >= 'a' && c <= 'z')
    {
        return c - 'a' + 10;
    }
    if (c >= 'A' && c <= 'Z')
    {
        return c - 'A' + 10;
    }
    return c;
}
// URL解码
static std::string UrlDecode(const std::string &url, bool convert_plus_to_space)
{
    std::string res;
    for (auto i = 0; i < url.size(); i++)
    {
        if (url[i] == '%')
        {
            char v1 = HEXTOI(url[i + 1]);
            char v2 = HEXTOI(url[i + 2]);
            char v = (v1 << 4) + v2;
            res += v;
            i += 2;
        }
        else if (convert_plus_to_space && url[i] == '+')
        {
            res += ' ';
        }
        else
        {
            res += url[i];
        }
    }
    return res;
}
// 响应状态码的描述信息获取
static std::string StatuDesc(int status)
{
    std::unordered_map<int, std::string> desc_map = {
        {200, "OK"},
        {400, "Bad Request"},
        {404, "Not Found"},
        {405, "Method Not Allowed"},
        {500, "Internal Server Error"}};
    auto it = desc_map.find(status);
    if (it == desc_map.end())
    {
        return "Unknown";
    }
    return it->second;
}
// 根据文件后缀名获取文件mime
static std::string ExtMime(std::string ext)
{
    std::unordered_map<std::string, std::string> mime_map = {
        {".html", "text/html"},
        {".css", "text/css"},
        {".js", "application/javascript"},
        {".png", "image/png"},
        {".jpg", "image/jpeg"},
        {".gif", "image/gif"},
        {".svg", "image/svg+xml"},
        {".ttf", "application/x-font-ttf"},
        {".woff", "application/font-woff"},
        {".woff2", "font/woff2"},
        {".eot", "application/vnd.ms-fontobject"},
        {".otf", "font/otf"},
        {".ico", "image/x-icon"},
        {".json", "application/json"},
        {".xml", "application/xml"},
        {".txt", "text/plain"},
        {".pdf", "application/pdf"},
        {".zip", "application/zip"},
        {".tar", "application/x-tar"},
        {".gz", "application/x-gzip"},
        {".mp3", "audio/mpeg"},
        {".mp4", "video/mp4"},
        {".avi", "video/x-msvideo"},
        {".mov", "video/quicktime"},
        {".wmv", "video/x-ms-wmv"},
        {".flv", "video/x-flv"},
        {".swf", "application/x-shockwave-flash"},
        {".psd", "image/vnd.adobe.photoshop"},
        {".doc", "application/msword"},
        {".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
        {".xls", "application/vnd.ms-excel"},
        {".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
        {".ppt", "application/vnd.ms-powerpoint"},
        {".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"}};
    size_t pos = ext.find_last_of('.'); // 查找文件后缀名的位置
    if (pos == std::string::npos)
    {
        return "application/octet-stream";
    }
    std::string suffix = ext.substr(pos); // 获取文件后缀名
    auto it = mime_map.find(suffix);
    if (it == mime_map.end())
    {
        return "application/octet-stream";
    }
    return it->second;
}

// 判断一个文件是否是一个目录
static bool IsDirectory(const std::string filename)
{
    struct stat st;
    int ret = stat(filename.c_str(), &st);
    if (ret < 0)
    {
        return false;
    }
    return S_ISDIR(st.st_mode);
}
// 判断一个文件是否是一个普通文件
static bool IsRegularFile(const std::string filename)
{
    struct stat st;
    int ret = stat(filename.c_str(), &st);
    if (ret < 0)
    {
        return false;
    }
    return S_ISREG(st.st_mode);
}

// http请求的资源路径有效性判断
bool IsValidPath(const std::string &path)
{
    std::vector<std::string> subdir;
    Split(path, "/", &subdir);
    int level = 0;
    for (auto &s : subdir)
    {
        if (s == "..")
        {
            level--;
            if (level < 0)
                return false;
        }
        else
        {
            level++;
        }
    }
    return true;
}
int main()
{
    std::cout<<IsValidPath("/a/b/c/d")<<std::endl;
    std::cout<<IsValidPath("/a/../c/d")<<std::endl;
    std::cout<<IsValidPath("/a/../../c/d")<<std::endl;


    // std::cout << IsRegularFile("any.cpp") << std::endl;
    // std::cout << IsRegularFile("test") << std::endl;
    // std::cout << IsDirectory("any.cpp") << std::endl;
    // std::cout << IsDirectory("test") << std::endl;

    // std::cout << StatuDesc(2000) << std::endl;
    // std::cout << ExtMime(".html.e") << std::endl;

    // std::string url = "http://www.baidu.com/s?wd=hello%20world: C  ";
    // std::string encoded_url = UrlEncode(url, true);
    // std::string decoded_url = UrlDecode(encoded_url, true);
    // std::cout << "encoded_url:" << encoded_url << std::endl;
    // std::cout << "decoded_url:" << decoded_url << std::endl;

    // std::string path = "./eventfd.cc";
    // std::string buf;
    // if (ReadFile(path, &buf) == false)
    // {
    //     return -1;
    // }
    // std::cout << "buf:" << buf << std::endl;

    // std::string filename = "test.txt";
    // WriteFile(filename, buf);

    /*
    std::string str = "abc,,,,,bcd,cde,";
    std::vector<std::string> res;
    Split(str, ",", &res);
    for (auto s : res)
    {
        std::cout << "[" << s << "]" << std::endl;
    }*/
    return 0;
}